home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1995 April / Internet Tools.iso / x25 / nrs.shar.Z / nrs.shar / wdbm.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-04-27  |  16.9 KB  |  656 lines

  1. #ifndef    lint
  2. static char rcsid[]="CUCL $Header: wdbm.c,v 2.3 86/11/18 08:07:37 pb Exp $";
  3. #endif    lint
  4.  
  5. THIS IS JUST INCLUDED IN THE DISTRIBUTION AS AN EXAMPLE
  6.  
  7. PLEASE CONTACT ME FOR THE LATEST VERSION
  8.  
  9. /*
  10.  * This software may be used or copied by anyone so long as it is not sold
  11.  * for profit, and that the gist of this header is retained.
  12.  * 
  13.  * Anyone finding a bug/feature/extension should contact the author in the
  14.  * first instance.
  15.  * 
  16.  * (c) Piete Brooks <pb@cl.cam.ac.uk> Cambridge Univ Comp Lab, UK.  Feb 1985
  17.  *
  18.  *    $State: Exp $
  19.  * $Log:    wdbm.c,v $
  20.  * Revision 2.3  86/11/18  08:07:37  pb
  21.  * Overwrite with the REAL version .....
  22.  * 
  23.  */
  24.  
  25. /*
  26.  * Compilation:
  27.  * 
  28.  *     cc wdbm -I<york header directory> -l<york library name>
  29.  * eg     cc wdbm -I/usr/src/x25 -lx25
  30.  * 
  31.  * If only text->text is required, add -DTEXT_ONLY
  32.  *
  33.  * This was written for the dbm code I put into D2.2
  34.  * I have been unable to aquire a pre-release copy of D2.2 from york or spider
  35.  * to see what mods they have made to it, so this may need some mods.
  36.  * If you have any problems, PLEASE MAIL ME & I'll try to fix them.
  37.  *
  38.  * I have not fully tested (if at all):
  39.  * 
  40.  * non dbm use
  41.  * many others
  42.  *
  43.  * but I repeat -- Please let ME know of any problems so I can fix them &
  44.  * distribute fixes.
  45.  */
  46.  
  47. /*     Usage: wdbm [options] [destination]
  48.  * 
  49.  *     normal use: wdbm
  50.  * 
  51.  * This program takes a directory file (see netdir(5)), and generates a binary
  52.  * version for direct access with dbm operations or a text version.
  53.  * In the case of the binary, it stores the information three times:
  54.  * the standard name, the abbreviated name & the address.
  55.  * The names are stored with all the leading domains which match with the
  56.  * current domain stripped.
  57.  * The latter is infact only part of the address as defined by base_addr(addr)
  58.  * so as to ensure that the suffices are ignored in the initial lookup.
  59.  * 
  60.  * Source file format:
  61.  *
  62.  * #<anything>        ignore this line
  63.  * 
  64.  * <anythingelse>    process this line
  65.  *
  66.  * 
  67.  * Piete Brooks, University Cambridge Computer Laboratory, Feb 85
  68.  */
  69.  
  70. #include "local.h"
  71. #include "netio.h"
  72. #include "tdir.h"
  73. #include "nets.h"
  74. #ifndef    TEXT_ONLY
  75. #include "ndbm.h"
  76. #endif    TEXT_ONLY
  77. #include <errno.h>
  78. #include <stdio.h>
  79. #include <sys/types.h>
  80. #include <sys/stat.h>
  81.  
  82. /* Well, good old spider went & removed all the debug code !! */
  83. #ifndef    deb
  84. /*
  85.  * The debugging package:
  86.  * By default have it ON:  may be turned OFF in local.h
  87.  */
  88. #ifdef    NODEBUG
  89. #undef    DEBUG
  90. #define deb(n, rest)
  91. #else    NODEBUG
  92. #define    DEBUG
  93. #endif    NODEBUG
  94.  
  95. #define    D_USER    0
  96. #define    D_ADDR    1
  97. #define    D_NET    2
  98. #define    D_SIZE    (D_NET + 1)
  99.  
  100. #ifndef    D_DEF
  101. #define    D_DEF    D_USER
  102. #endif    D_DEF
  103. #define    COMMA ,
  104. int     debug_v[D_SIZE];
  105. #define    debug            debug_v[D_DEF]
  106.  
  107. /*
  108.     SO: you can do:    cc -DD_DEF=<x>
  109.     or:
  110.             #define    D_DEF    <x> in header
  111. */
  112. /*
  113.  *    Define a deb(n, text) macro, and COMMA (to be used in place of ',' in
  114.  * all deb statements. Typical use is:
  115.  *    deb(10, "Simple text");
  116.  *    deb(20, "Complex text" COMMA arg1 COMMA arg2)
  117.  */
  118. #ifndef    NODEBUG
  119. #define deb(n, rest)        if (debug > n) fprintf(stderr, rest)
  120. #define    set_low_deb(x)        { debug_v[D_ADDR] = x; debug_v[D_NET] = x; }
  121. #define deb_l(l, n, rest)    if (debug_v[l]     > n) fprintf(stderr, rest)
  122. #endif    NODEBUG
  123. #endif    deb
  124.  
  125. /* In their wisdom, york/spider decided to make an incompatible change */
  126. #ifndef    SIGNED_C
  127. #define    SIGNED_C    short
  128. #endif    SIGNED_C
  129.  
  130. extern  errno;
  131.  
  132. /* Table to convert from a network name (e.g. JANET) to a single letter */
  133. struct nets {
  134.     char    n_char;
  135.     char   *n_string;
  136. }           nets[] = {
  137.     {    NETc_JANET,    NETs_JANET    },
  138.     {    NETc_PSS,    NETs_PSS    },
  139.     {    NETc_LOCAL,    NETs_LOCAL    },
  140.     {    NETc_IPSS,    NETs_IPSS    },
  141.     {    0                }
  142. };
  143.  
  144. #ifndef    TEXT_ONLY
  145. DBM_t * dbm;
  146. #endif    TEXT_ONLY
  147.  
  148. char   *gets(), *base_addr(), *strip_std(), *unstrip_std(), *index();
  149. struct tdirent *gettdadr(), *parse_directory_line();
  150.  
  151. extern    char *optarg;
  152. extern    int  getopt(), optind;
  153. char    getopt_arg[] = "d:D:aco:Ortu";
  154. char    USAGE[] = "Usage: %s [-d(ebug)] [-D(ebug)] [-n(ocompat)] [-c(ompress-off)]\n\t[-a(dd)] [-r(emove)] [-t(ext)] [-U(pdate)] [-o(utputfile)] [source]\n";
  155. char    PAG[] = ".pag";
  156. char    DIR[] = ".dir";
  157. char    TEMP[] = "-t";
  158. char    new_line[2048];
  159. char    *nl_ptr;
  160.  
  161. main(argc, argv)
  162. char  **argv;
  163. {
  164.     char    line[2048];
  165.     char    split_line[2048];
  166.     char    name[2048];
  167.     char    data_buff[2048];
  168.     char    dummy[2048];
  169.     char    destination_filename[2048];
  170.     char   *out_filename;
  171.     char   *in_filename;
  172. #ifndef    TEXT_ONLY
  173.     Datum_t data;
  174.     Datum_t key;
  175.     Datum_t T_last;
  176. #endif    TEXT_ONLY
  177.     int     fd;
  178.     int     store_failed = 0;    /* how many times have dbm_add failed */
  179.     int     old_dir = 0;    /* Is this an old format directory ? */
  180.     int     lineno;        /* source line number    */
  181.     int     c;
  182.     char   *commandname = *argv;
  183.     int     compress = 1;    /* Should the JANET:0: -> J ? */
  184. #ifndef    TEXT_ONLY
  185.     int        text = 0;        /* am I producing text ? */
  186. #else    TEXT_ONLY
  187.     int        text = 1;
  188. #endif    TEXT_ONLY
  189.     int     upd = 0;        /* should I update the DBM in situ */
  190.     int     replace = 0;    /* am I replacing an entry */
  191.     int     add = 0;        /* am I adding extra entries */
  192.     int     remove = 0;        /* am I removng entries */
  193.     int     exists = 0;        /* does the DBM exist already */
  194.  
  195.     struct stat sbuf;
  196.     struct stat *sbp = &sbuf;
  197.  
  198. #ifndef    TEXT_ONLY
  199.     data.dptr = data_buff;
  200.     key.dptr = name;
  201. #endif    TEXT_ONLY
  202.  
  203.     while ((c = getopt(argc, argv, getopt_arg)) != EOF)
  204.     switch (c) {
  205. #ifdef    DEBUG
  206.         case 'd':    debug = atoi(optarg);            break;
  207.         case 'D':    set_low_deb(atoi(optarg));        break;
  208. #endif    DEBUG
  209.         case 't':    text    =1;    deb(3, "text\n");    break;
  210.         case 'c':    compress= 0;    deb(3, "nocompress\n");    break;
  211.         case 'o':    out_filename = optarg;            break;
  212.         case 'O':    old_dir = 1;    deb(3, "old format\n");    break;
  213.         case 'r':    remove    = 1;    deb(3, "remove\n");    break;
  214.         case 'a':    add    = 1;    deb(3, "add\n");    break;
  215.         case 'u':    upd    = 1;    deb(3, "update\n");    break;
  216.         default:    printf(USAGE, commandname);        exit(1);
  217.     }
  218.  
  219.     argc -= optind;
  220.     argv += optind;
  221.  
  222.     /* If no output file, then use stout for text, else the std dbm */
  223.     if (out_filename == CNULL)
  224.     out_filename = (text) ? "-" : ADDRESSFILE;
  225.  
  226.     /*     One file -- default input == output */
  227.     if (argc > 0)
  228.     in_filename = argv[0];
  229.     else
  230.     in_filename = (text) ? "-" : out_filename;
  231.  
  232.     strcpy(destination_filename, out_filename);
  233.     out_filename = destination_filename;
  234.  
  235.     deb(2, "Process %s to %s\n" COMMA
  236.         in_filename COMMA out_filename);
  237.  
  238.     /*     Open the input file     */
  239.     if (strcmp(in_filename, "-")) {
  240.     fclose(stdin);
  241.     if (fopen(in_filename, "r") != stdin)
  242.         die("Failed to open '%s' as stdin: ", in_filename);
  243.     }
  244.     if (text && strcmp(out_filename, "-")) {
  245.     fclose(stdout);
  246.     if (fopen(out_filename, "w") != stdout)
  247.         die("Failed to open '%s' as stdout: ", out_filename);
  248.     }
  249.  
  250. #ifndef    TEXT_ONLY
  251.  /* 
  252.   for my sins check if db exists, if so open old one to add to 
  253.   the sin is assuming that if <dir> exists then <dir>.DIR/PAG 
  254.   does too (sigh) 
  255.   */
  256.     if (!text)
  257.     { if (!upd && !add && !stat(out_filename, sbp)) {
  258.         /* DB exists: Do not process the working file !! Make a temp copy */
  259.     deb(3, "creating new database...");
  260.     strcat(out_filename, TEMP);
  261.  
  262.     /*  And the two output files ...     */
  263.     strcpy(line, out_filename);
  264.     strcat(line, PAG);
  265.     fd = creat(line, 0777);
  266.     if (fd < 0)
  267.         die("Failed to creat %s: ", line);
  268.     deb(3, "%s created OK\n" COMMA line);
  269.     close(fd);
  270.  
  271.     strcpy(line, out_filename);
  272.     strcat(line, DIR);
  273.     fd = creat(line, 0777);
  274.     if (fd < 0)
  275.         die("Failed to creat %s: ", line);
  276.     deb(3, "%s created OK\n" COMMA line);
  277.     close(fd);
  278.     exists = 0;
  279.     }
  280.     else {
  281.     deb(3, "Using old database %s\n" COMMA out_filename);
  282.     exists = 1;
  283.     }
  284.     if (!(dbm = ndbmopen(out_filename, 2, 0))) {
  285.     fprintf(stderr, "Failed to open %s: ", out_filename);
  286.     perror("");
  287.     exit(1);
  288.     }
  289.     }
  290. #endif    TEXT_ONLY
  291. deb(0,"setting domain\n");
  292.     set_domain_default();
  293. deb(0, "domain set\n");
  294.  
  295.  /*     Now process the data     */
  296.     for (lineno = 1; gets(line) != CNULL; lineno++) {
  297.     struct tdirent *tdir;
  298.  
  299.     /* Comment ?  Look for progmat. (none at the moment) */
  300.     if (*line == '#') {
  301.         if (text)    printf("%s\n", line);
  302.         continue;
  303.     }
  304.  
  305. #ifndef    TEXT_ONLY
  306.     /*
  307.      * Just remove the key given
  308.      */
  309.     if (remove) {
  310.     /*     Ensure the KEY is correct     */
  311.         Datum_t D_last;
  312.         key.dptr = line;
  313.         deb(1, "deleting [%s]\n" COMMA key.dptr);
  314.         key.dsize = strlen(key.dptr);
  315.         if (dbmdelete(dbm, key) != 0)
  316.         deb(0, "delete of %s failed\n" COMMA key.dptr);
  317.         continue;
  318.     }
  319. #endif    TEXT_ONLY
  320.  
  321.     /* make a copy of the data and parse it */
  322.     strcpy(split_line, line);
  323.     if (tdir = parse_directory_line(split_line)) {
  324.         char   *addr_hash = base_addr(tdir->td_address);
  325.         char    compressed    = 0;
  326.         char    known_net    = 0;
  327.         char    name_[128];
  328.         char    abbrev_[128];
  329.         char   *name;
  330.         char   *abbrev;
  331.         int     relay;
  332.         SIGNED_C prefix;
  333.         SIGNED_C a_prefix;
  334.  
  335.     /*     Replace 'X' with 'Y' if / in name     */
  336.         if (index(tdir->td_address, '/')) {
  337.         char   *change;
  338.         if (change = index(tdir->td_services, X25SERVICE))
  339.             *change = YBSERVICE;
  340.         if (change = index(tdir->td_rev_services, X25SERVICE))
  341.             *change = YBSERVICE;
  342.         }
  343. #ifdef    DIR_COMPAT
  344.         if (old_dir) {    /* Convert TS29->YB */
  345.         char   *change;
  346.         if (change = index(tdir->td_services, 'T'))
  347.             *change = YBSERVICE;
  348.         if (change = index(tdir->td_rev_services, 'T'))
  349.             *change = YBSERVICE;
  350.         }
  351. #endif    DIR_COMPAT
  352.  
  353.         /*
  354.          * Now let's rebuild the line from scratch ....
  355.          */
  356.         if (compress)
  357.         {    struct nets *p;
  358.  
  359.         /*     Known Network ?     */
  360.         for (p = nets; p->n_char; p++)
  361.             if (! cistrcmp(p->n_string, tdir->td_network))
  362.             {    known_net = p->n_char;
  363.                 if (tdir->td_flags[TDFS_isunix] == 0 ||
  364.                     tdir->td_flags[TDFS_isunix] == TDF_isunix)
  365.                     compressed = known_net |
  366.                     ((tdir->td_flags[TDFS_isunix]) ?
  367.                         DBM_isunix : 0);
  368.                 break;
  369.             }
  370.         }
  371.  
  372.         unstrip_std(name_, sizeof name_, tdir->td_name, tdir->td_prefix);
  373.         unstrip_std(abbrev_, sizeof abbrev_, tdir->td_abbrev, tdir->td_a_prefix);
  374.         name = strip_std(name_, &prefix);
  375.         abbrev = strip_std(abbrev_, &a_prefix);
  376.  
  377.         nl_ptr = new_line;
  378.         if (compressed)    adds("%c" COMMA compressed);
  379.         else
  380.         {    
  381.         /* The flags */
  382.         if (!compress || tdir->td_flags[0])
  383.                     adds("%x", tdir->td_flags[0]);
  384.         addcolon();
  385.  
  386.         /* The network */
  387.         if (known_net)        adds("%c", known_net);
  388.         else            adds("%s", tdir->td_network);
  389.         addcolon();
  390.         }
  391.  
  392.         /* The services */
  393.         if (! cistrcmp(tdir->td_services, tdir->td_rev_services))
  394.             adds("%s", tdir->td_services);
  395.         else    adds("%s|%s", tdir->td_services,
  396.                       tdir->td_rev_services);
  397.         addcolon();
  398.  
  399.         /* The names */
  400.         if (! cistrcmp(name, abbrev))
  401.             adds("%s", name);
  402.         else    adds("%s|%s", name, abbrev);
  403.         addcolon();
  404.  
  405.         /* The address */
  406.         adds("%s", tdir->td_address);
  407.         addcolon();
  408.  
  409.         /* The preficies */
  410.         if (prefix == a_prefix)
  411.             adds("%d", prefix);
  412.         else    adds("%d|%d", prefix, a_prefix);
  413.         addcolon();
  414.  
  415.         /* The application relays */
  416.         for (relay=0; relay < MAX_AR && tdir->td_ars[relay]; relay++)
  417.         {    int len = strlen(new_line);
  418.             adds("%s%s", (relay) ? "|" : "", tdir->td_ars[relay]);
  419.         if (len >= MAX_DIRLEN -2)
  420.         {    printf("Remove `%s' from %s\n", new_line+len+1, name);
  421.             new_line[len] = '\0';
  422.         }
  423.         }
  424.         addcolon();
  425.  
  426.         /* The comment */
  427.         /* If this is about to overrun, then chop it ! */
  428.         if (strlen(new_line) + strlen(tdir->td_text) >= MAX_DIRLEN-1)
  429.         {    static char elipsis[] = "...";
  430.         int spare = MAX_DIRLEN-1 - strlen(new_line) - sizeof elipsis;
  431.         printf("Truncate comment field `%s' for %s\n", tdir->td_text, name);
  432.         if (spare > 0)
  433.             adds("%.*s%s", spare, tdir->td_text, elipsis);
  434.         }
  435.         else adds("%s", tdir->td_text);
  436.  
  437.         deb(1, "%3d <%s> -> <%s>\n" COMMA lineno COMMA line COMMA new_line);
  438.  
  439.         strcpy(line, new_line);
  440.  
  441.         if (strlen(line) >= MAX_DIRLEN-1) {
  442.         printf("Bad line %5d ignored: %d (>%d) chars `%s'\n",
  443.             lineno, strlen(line), MAX_DIRLEN - 2, line);
  444.         /*??*/
  445.         continue;
  446.         }
  447.  
  448.         if (text)
  449.         printf("%s\n", line);
  450. #ifndef    TEXT_ONLY
  451.         else {
  452.         strcpy(split_line, line);
  453.         parse_directory_line(split_line);
  454.  
  455.         strcpy(key.dptr, tdir->td_name);
  456.  
  457.     /*     Anything in the FORWARD direction ? */
  458.         if (tdir->td_services) {
  459.         /*     Ensure the KEY is correct     */
  460.         deb(1, " [%s]\n" COMMA key.dptr);
  461.         key.dsize = strlen(key.dptr);
  462.         if (key.dsize)
  463.         {   T_last = dbmfetch(dbm, key);
  464.             if (T_last.dptr) {
  465.             if (upd == 0) {
  466.                 deb(5, "<< add to\n%s\n" COMMA T_last.dptr);
  467.                 strcpy(data.dptr, T_last.dptr);
  468.                 strcat(data.dptr, "\n");
  469.                 strcat(data.dptr, line);
  470.                 deb(5, "%d bytes>>\n" COMMA strlen(data.dptr));
  471.             }
  472.             else {
  473.                 strcpy(data.dptr, line);
  474.                 deb(5, "replacing %s\n with %s\n" COMMA T_last.dptr COMMA data.dptr);
  475.                 replace = 1;
  476.             }
  477.             }
  478.             else
  479.             strcpy(data.dptr, line);
  480.  
  481.             data.dsize = strlen(data.dptr) + 1;
  482.             if (data.dsize > 1000)
  483.             deb(0, "store ...");
  484.             if (dbmstore(dbm, key, data, 1)) {
  485.             store_failed++;
  486.             if (data.dsize > 1000)
  487.                 deb(0, "Failed\n");
  488.             deb(10, "Store failed on `%s'\n" COMMA data.dptr);
  489.             }
  490.             if (data.dsize > 1000)
  491.             deb(0, "Failed\n");
  492.             deb(50, "[[ Store OK on `%s' ]]\n" COMMA data.dptr);
  493.         }
  494.         else printf("Null long forward key in `%s' -- ignored\n", line);
  495.         /* abbreviated form? */
  496.         if (tdir->td_abbrev && tdir->td_abbrev != tdir->td_name &&
  497.             strcmp(tdir->td_abbrev, tdir->td_name)) {
  498.             strcpy(key.dptr, tdir->td_abbrev);
  499.             key.dsize = strlen(key.dptr);
  500.             if (key.dsize)
  501.             {    T_last = dbmfetch(dbm, key);
  502.             if (T_last.dptr) {
  503.                 if (upd == 0) {
  504.                 deb(5, "<< add to\n%s\n" COMMA T_last.dptr);
  505.                 strcpy(data.dptr, T_last.dptr);
  506.                 strcat(data.dptr, "\n");
  507.                 strcat(data.dptr, line);
  508.                 deb(5, "%d bytes>>\n" COMMA strlen(data.dptr));
  509.                 }
  510.                 else {
  511.                 strcpy(data.dptr, line);
  512.                 deb(5, "replacing %s\n with %s\n" COMMA T_last.dptr COMMA data.dptr);
  513.                 replace = 1;
  514.                 }
  515.             }
  516.             else
  517.                 strcpy(data.dptr, line);
  518.  
  519.             data.dsize = strlen(data.dptr) + 1;
  520.             if (data.dsize > 1000)
  521.                 deb(0, "store ...");
  522.             if (dbmstore(dbm, key, data, 1)) {
  523.                 store_failed++;
  524.                 if (data.dsize > 1000)
  525.                 deb(0, "Failed\n");
  526.                 deb(10, "Store failed on `%s'\n" COMMA data.dptr);
  527.             }
  528.             if (data.dsize > 1000)
  529.                 deb(0, "Failed\n");
  530.             deb(50, "[[ Store OK on `%s' ]]\n" COMMA data.dptr);
  531.             }
  532.               else printf("Null abbreviated forward key in `%s' -- ignored\n", line);
  533.  
  534.         }
  535.         }
  536.  
  537.     /*     Anything in the REVERSE direction ? */
  538.         if (*tdir->td_rev_services) {
  539.         if (addr_hash != CNULL && *addr_hash) {
  540.         /*     Ensure the KEY is correct     */
  541.             strcpy(key.dptr, addr_hash);
  542.             deb(1, " [%s] " COMMA key.dptr);
  543.             key.dsize = strlen(key.dptr);
  544.             T_last = dbmfetch(dbm, key);
  545.             if (T_last.dptr) {
  546.             if (replace == 0) {
  547.                 deb(5, "<< add to (%s)\n%s\n" COMMA addr_hash COMMA T_last.dptr);
  548.                 strcpy(data.dptr, T_last.dptr);
  549.                 strcat(data.dptr, "\n");
  550.                 strcat(data.dptr, line);
  551.                 deb(5, "%d bytes>>\n" COMMA strlen(data.dptr));
  552.             }
  553.             else {
  554.                 strcpy(data.dptr, line);
  555.                 deb(5, "replaced [%s]\n with [%s]\n" COMMA T_last.dptr COMMA data.dptr);
  556.                 replace = 0;
  557.             }
  558.             }
  559.             else
  560.             strcpy(data.dptr, line);
  561.  
  562.             data.dsize = strlen(data.dptr) + 1;
  563.             if (data.dsize > 1000)
  564.             deb(0, "store ...");
  565.             if (dbmstore(dbm, key, data, 1)) {
  566.             store_failed++;
  567.             if (data.dsize > 1000)
  568.                 deb(0, "Failed\n");
  569.             deb(10, "Store failed on `%s'\n" COMMA data.dptr);
  570.             }
  571.             if (data.dsize > 1000)
  572.             deb(0, "Failed\n");
  573.             deb(50, "[[ Store OK on `%s' ]]\n" COMMA data.dptr);
  574.         }
  575.         else
  576.             deb(0, "No address in `%s'\n" COMMA line);
  577.         }
  578.         deb(1, "\n");
  579.         }
  580. #endif    TEXT_ONLY
  581.     }
  582.     else
  583.         printf("Bad line %5d at field %d: '%s'\n",
  584.             lineno, fd, line);
  585.     }
  586. #ifndef    TEXT_ONLY
  587.     if (store_failed)
  588.     printf("Store failed %d time%s\n",
  589.         store_failed, (store_failed == 1) ? "" : "s");
  590.  
  591.  /*     Now rename it     */
  592.     if (!text && !exists) {
  593.     /* created in temp files rather than just updating */
  594.     strcpy(line, out_filename);
  595.     strcat(line, PAG);
  596.     strcpy(split_line, out_filename);
  597.     split_line[strlen(split_line) - (sizeof TEMP - 1)] = 0;
  598.     strcat(split_line, PAG);
  599.     mv(split_line, line);
  600.     strcpy(line, out_filename);
  601.     strcat(line, DIR);
  602.     strcpy(split_line, out_filename);
  603.     split_line[strlen(split_line) - (sizeof TEMP - 1)] = 0;
  604.     strcat(split_line, DIR);
  605.     mv(split_line, line);
  606.     }
  607. #endif    TEXT_ONLY
  608.     exit(0);
  609. }
  610.  
  611. addcolon()
  612. {
  613.     *nl_ptr++ = ':';
  614.     *nl_ptr   = '\0';
  615. }
  616.  
  617. /*VARARGS 1*/
  618. adds(format, a1,a2,a3,a4,a5,a6)
  619. char *format;
  620. {    char *p;
  621.     sprintf(nl_ptr, format, a1,a2,a3,a4,a5,a6);
  622.     while (p = index(nl_ptr, ':'))
  623.     {    *p = COLON;
  624.         nl_ptr = p+1;
  625.     }
  626.     while (*nl_ptr) nl_ptr++;
  627. }
  628.  
  629. #ifndef    TEXT_ONLY
  630. mv(to, from)
  631. char   *to,
  632.        *from;
  633. {
  634.     if (unlink(to) && errno != ENOENT) {
  635.     fprintf(stderr, "Failed to unlink %s: ", to);
  636.     perror("");
  637.     }
  638.     else
  639.     if (link(from, to) == 0)
  640.         unlink(from);
  641.     else {
  642.         fprintf(stderr, "Failed to move %s to %s: ", from, to);
  643.         perror("");
  644.     }
  645. }
  646. #endif    TEXT_ONLY
  647.  
  648. /* VARARGS1 */
  649. die(s, a, b, c, d, e, f, g)
  650. char   *s;
  651. {
  652.     fprintf(stderr, s, a, b, c, d, e, f, g);
  653.     perror("");
  654.     exit(1);
  655. }
  656.